#include "lista_circular.h"
/**********************************************************************/
/**********************************************************************/
/* Crear_Lista: Ver lista.h */ 
bool Crear_Lista (tlista *lista){
	lista->primer_nodo = NULL;
	lista->ultimo_nodo = NULL;
	lista->largo = 0;
	return true;
}

/**********************************************************************/
/* Lista_Vacia: Ver lista.h */
bool Lista_Vacia (tlista lista){
    return (lista.largo == 0);
}
    
/**********************************************************************/
/* Insertar_nodo_Primero */
bool insertar_nodo_primero (tnodol **primer_nodo, tnodol **ultimo_nodo, tdatol dato) {
	tnodol* aux = (tnodol*) malloc (sizeof (tnodol));
	if (aux == NULL)
		return false;
	
	tnodol* nodo_nuevo = aux;
	nodo_nuevo->dato = dato;
	nodo_nuevo->siguiente = *primer_nodo;
	if (*ultimo_nodo == NULL) {
		nodo_nuevo->siguiente = nodo_nuevo;
		*ultimo_nodo = nodo_nuevo;
	}else
		(*ultimo_nodo)->siguiente = nodo_nuevo;
	*primer_nodo = nodo_nuevo;
	return true;
}

/**********************************************************************/
/* Insertar_Lista_Primero: Ver lista.h */
bool Insertar_Lista_Primero (tlista *lista, tdatol dato){
	if (insertar_nodo_primero (&lista->primer_nodo, &lista->ultimo_nodo, dato)) {
		
		lista->largo++;
		return true;
	}
	return false;
}

/**********************************************************************/
/* Insertar_Lista_Final: Ver lista.h */
bool Insertar_Lista_Final (tlista *lista, tdatol dato) {
	if (Insertar_Lista_Primero (lista, dato)) {
		lista->primer_nodo = lista->primer_nodo->siguiente;
		lista->ultimo_nodo = lista->ultimo_nodo->siguiente;
		return true;
	}
	return false;
}

/**********************************************************************/
/* Borrar_nodo_Primero: Se elimina el primer nodo de la lista y se devuel-
 * ve el valor almacenado en el mismo */
bool borrar_nodo_primero (tnodol **primer_nodo, tnodol **ultimo_nodo, tdatol *dato) {
	tnodol *aux = *primer_nodo;
	*dato = aux->dato;
	if (*primer_nodo != *ultimo_nodo) {
		(*ultimo_nodo)->siguiente = aux->siguiente;
		*primer_nodo = aux->siguiente;
	}else{
		*primer_nodo = NULL;
		*ultimo_nodo = NULL;
	}
	free (aux);
	return true;
}

/**********************************************************************/
/* Borrar_Lista_Primero: Se elimina el primer nodo de la lista y se devuel-
 * ve el valor almacenado en el mismo */
bool Borrar_Lista_Primero (tlista *lista, tdatol *dato){
	if (Lista_Vacia (*lista))
		return false;
	if (borrar_nodo_primero (&lista->primer_nodo, &lista->ultimo_nodo, dato)) {
		lista->largo--;
		return true;
	}
	return false;
}

/**********************************************************************/
/* Listar_Primero: Devuelve el dato señalado por el primer nodo, si la 
 * lista no es vacía */
bool Listar_Pimero (const tlista *lista, tdatol *dato){
	if (!Lista_Vacia(*lista)) {
		*dato = lista->primer_nodo->dato;
		return true;
	}
	return false;
}

/**********************************************************************/
/* Destruir_Lista: Ver lista.h */
bool Destruir_Lista (tlista *lista, destruir_contenido destruir_contenido){
	tlista_iter iter;
	void* dato;
	Crear_Lista_Iter(lista, &iter);
	while (!Lista_Iter_Final(&iter)) {
		Borrar_Lista_Primero(lista, &dato);
		destruir_contenido(dato);
		iter.primer_nodo = lista->primer_nodo;
		Avanzar_Lista_Iter(&iter);
	}
	if (!Lista_Vacia(*lista)) {
		Borrar_Lista_Primero(lista, &dato);
		destruir_contenido(dato);
	}
	lista->primer_nodo = NULL;
	lista->ultimo_nodo = NULL;
	return true;
}

/********************************************************************/
/* Crear_Lista_Iter: Ver lista.h */
bool Crear_Lista_Iter(tlista *lista, tlista_iter *iter){
	iter->primer_nodo = lista->primer_nodo;
	iter->actual = lista->primer_nodo;
	iter->anterior = lista->ultimo_nodo; //antes era NULL;	
	iter->vuelta = 0;					
	return true;
}
	
/********************************************************************/
/* Lista_Iter_Final: 
 * si esta en el 1er nodo en la 1er vuelta, no se considera final
 */
bool Lista_Iter_Final (tlista_iter *iter){
	return (iter->actual == iter->primer_nodo && iter->vuelta != 0);					
}

/********************************************************************/
/* Avanzar_Lista_iter: Ver lista.h */
bool Avanzar_Lista_Iter (tlista_iter *iter){
	//if (Lista_Iter_Final(iter))    ???
	//	return false;
	iter->anterior = iter->actual;
	iter->actual = iter->actual->siguiente;
	if (iter->actual == iter->primer_nodo)
		iter->vuelta ++;
	return true;
}

/*********************************************************************/
/* Ver_Lista_Actual: Ver lista.h */
bool Ver_Lista_Actual ( tlista_iter *iter, tdatol * dato){
	if (Lista_Iter_Final (iter))
		return false;
	*dato = iter->actual->dato;
	return true;
}

/********************************************************************/
/* Redireccionar_Pincipio: Redirecciona el puntero que señala el 
 * principio de la lista */
bool Redireccionar_Principio (tlista *lista, tlista_iter *iter){
	tlista_iter iter_aux;
	Crear_Lista_Iter(lista, &iter_aux);
	if (iter->anterior == lista->ultimo_nodo) {
		lista->primer_nodo = iter->actual;
		iter->primer_nodo = iter->actual;
	}
	return true;
}
               
/********************************************************************/
/* Insertar_Lista: Ver lista.h */
bool Insertar_Lista (tlista *lista, tlista_iter * iter, tdatol dato) {
	if (insertar_nodo_primero(&iter->actual, &iter->anterior, dato)) {
		return (Redireccionar_Principio (lista, iter));
		lista->largo++;
	}
	return false;
}
		
/********************************************************************/
/* Borrar_Lista: Ver lista.h */
bool Borrar_Lista (tlista *lista, tlista_iter *iter, tdatol *dato){
	if (Lista_Iter_Final(iter)) 			// luego redireccionar lista
		return false;
	if (!borrar_nodo_primero(&iter->actual, &iter->anterior, dato))
		return false;
	lista->largo--;
	return (Redireccionar_Principio (lista, iter));
}
/********************************************************************/

size_t Largo_Lista (tlista lista) {
	return lista.largo;
}
